// complex standard header
#pragma once
#ifndef _COMPLEX_
#define _COMPLEX_
#ifndef RC_INVOKED
#include <cmath>
#include <sstream>
#include <ymath.h>

#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new

#ifndef _C_COMPLEX_T
#define _C_COMPLEX_T

struct _C_double_complex { // double complex
    double _Val[2];
};

struct _C_float_complex { // float complex
    float _Val[2];
};

struct _C_ldouble_complex { // long double complex
    long double _Val[2];
};
#endif // _C_COMPLEX_T

// COMPLEX _Val OFFSETS
#define _RE 0
#define _IM 1

_STD_BEGIN
using _Dcomplex_value = _CSTD _C_double_complex;
using _Fcomplex_value = _CSTD _C_float_complex;
using _Lcomplex_value = _CSTD _C_ldouble_complex;

template <class _Ty>
class complex;
template <>
class complex<float>;
template <>
class complex<double>;
template <>
class complex<long double>;

// CLASS TEMPLATE _Ctraits
template <class _Ty>
class _Ctraits { // complex traits for _Ty
public:
    static _Ty _Flt_eps() { // get epsilon
        return numeric_limits<_Ty>::epsilon();
    }

    static _Ty _Flt_max() { // get max
        return (numeric_limits<_Ty>::max)();
    }

    static _Ty _Cosh(_Ty _Left, _Ty _Right) { // return cosh(_Left) * _Right
        return _CSTD _Cosh((double) _Left, (double) _Right);
    }

    static short _Exp(_Ty* _Pleft, _Ty _Right, short _Exponent) { // compute exp(*_Pleft) * _Right * 2 ^ _Exponent
        double _Tmp = (double) *_Pleft;
        short _Ans  = _CSTD _Exp(&_Tmp, (double) _Right, _Exponent);
        *_Pleft     = (_Ty) _Tmp;
        return _Ans;
    }

    static _Ty _Infv() { // return infinity
        return numeric_limits<double>::infinity();
    }

    static bool _Isinf(_Ty _Left) { // test for infinity
        double _Tmp = (double) _Left;
        return _CSTD _Dtest(&_Tmp) == _INFCODE;
    }

    static bool _Isnan(_Ty _Left) { // test for NaN
        double _Tmp = (double) _Left;
        return _CSTD _Dtest(&_Tmp) == _NANCODE;
    }

    static _Ty _Nanv() { // return NaN
        return numeric_limits<double>::quiet_NaN();
    }

    static _Ty _Sinh(_Ty _Left, _Ty _Right) { // return sinh(_Left) * _Right
        return _CSTD _Sinh((double) _Left, (double) _Right);
    }

    static _Ty asinh(_Ty _Left) { // return asinh(_Left)
        constexpr _Ty _Ln2 = 0.69314718055994530941723212145817658L;

        bool _Neg = _Left < 0;
        _Ty _Ans;

        if (_Neg) {
            _Left = -_Left;
        }

        if (_Left < 2 / _Flt_eps()) {
            _Ans = log1p(_Left + _Left * _Left / (1 + sqrt(_Left * _Left + 1)));
        } else {
            _Ans = log(_Left) + _Ln2;
        }

        return _Neg ? -_Ans : _Ans;
    }

    static _Ty atan2(_Ty _Yval, _Ty _Xval) { // return atan(_Yval / _Xval)
        return _CSTD atan2((double) _Yval, (double) _Xval);
    }

    static _Ty cos(_Ty _Left) { // return cos(_Left)
        return _CSTD cos((double) _Left);
    }

    static _Ty exp(_Ty _Left) { // return exp(_Left)
        return _CSTD exp((double) _Left);
    }

    static _Ty ldexp(_Ty _Left, int _Exponent) { // return _Left * 2 ^ _Exponent
        return _CSTD ldexp((double) _Left, _Exponent);
    }

    static _Ty log(_Ty _Left) { // return log(_Left)
        return _CSTD log((double) _Left);
    }

    static _Ty log1p(_Ty _Left) { // return log(1 + _Left)
        if (_Left < -1) {
            return _Nanv();
        } else if (_Left == 0) {
            return _Left;
        } else { // compute log(1 + _Left) with fixup for small _Left
            _Ty _Leftp1 = 1 + _Left;
            return log(_Leftp1) - ((_Leftp1 - 1) - _Left) / _Leftp1;
        }
    }

    static _Ty pow(_Ty _Left, _Ty _Right) { // return _Left ^ _Right
        return _CSTD pow((double) _Left, (double) _Right);
    }

    static _Ty sin(_Ty _Left) { // return sin(_Left)
        return _CSTD sin((double) _Left);
    }

    static _Ty sqrt(_Ty _Left) { // return sqrt(_Left)
        return _CSTD sqrt((double) _Left);
    }

    static _Ty tan(_Ty _Left) { // return tan(_Left)
        return _CSTD tan((double) _Left);
    }

    static _Ty hypot(_Ty _Left, _Ty _Right) {
        return _CSTD hypot((double) _Left, (double) _Right);
    }
};

// CLASS _Ctraits<long double>
template <>
class _Ctraits<long double> { // complex traits for long double
public:
    using _Ty = long double;

    static _Ty _Flt_eps() { // get epsilon
        return LDBL_EPSILON;
    }

    static _Ty _Flt_max() { // get max
        return LDBL_MAX;
    }

    static _Ty _Cosh(_Ty _Left, _Ty _Right) { // return cosh(_Left) * _Right
        return _CSTD _LCosh(_Left, _Right);
    }

    static short _Exp(_Ty* _Pleft, _Ty _Right, short _Exponent) { // compute exp(*_Pleft) * _Right * 2 ^ _Exponent
        return _CSTD _LExp(_Pleft, _Right, _Exponent);
    }

    static _Ty _Infv() { // return infinity
        return numeric_limits<long double>::infinity();
    }

    static bool _Isinf(_Ty _Left) { // test for infinity
        return _CSTD _LDtest(&_Left) == _INFCODE;
    }

    static bool _Isnan(_Ty _Left) { // test for NaN
        return _CSTD _LDtest(&_Left) == _NANCODE;
    }

    static _Ty _Nanv() { // return NaN
        return numeric_limits<long double>::quiet_NaN();
    }

    static _Ty _Sinh(_Ty _Left, _Ty _Right) { // return sinh(_Left) * _Right
        return _CSTD _LSinh(_Left, _Right);
    }

    static _Ty asinh(_Ty _Left) { // return asinh(_Left)
        constexpr _Ty _Ln2 = 0.69314718055994530941723212145817658L;

        const bool _Neg = _Left < 0;
        _Ty _Ans;

        if (_Neg) {
            _Left = -_Left;
        }

        if (_Left < 2 / _Flt_eps()) {
            _Ans = log1p(_Left + _Left * _Left / (1 + sqrt(_Left * _Left + 1)));
        } else {
            _Ans = log(_Left) + _Ln2;
        }

        return _Neg ? -_Ans : _Ans;
    }

    static _Ty atan2(_Ty _Yval, _Ty _Xval) { // return atan(_Yval / _Xval)
        return _CSTD atan2l(_Yval, _Xval);
    }

    static _Ty cos(_Ty _Left) { // return cos(_Left)
        return _CSTD cosl(_Left);
    }

    static _Ty exp(_Ty _Left) { // return exp(_Left)
        return _CSTD expl(_Left);
    }

    static _Ty ldexp(_Ty _Left, int _Exponent) { // return _Left * 2 ^ _Exponent
        return _CSTD ldexpl(_Left, _Exponent);
    }

    static _Ty log(_Ty _Left) { // return log(_Left)
        return _CSTD logl(_Left);
    }

    static _Ty log1p(_Ty _Left) { // return log(1 + _Left)
        if (_Left < -1) {
            return _Nanv();
        } else if (_Left == 0) {
            return _Left;
        } else { // compute log(1 + _Left) with fixup for small _Left
            _Ty _Leftp1 = 1 + _Left;
            return log(_Leftp1) - ((_Leftp1 - 1) - _Left) / _Leftp1;
        }
    }

    static _Ty pow(_Ty _Left, _Ty _Right) { // return _Left ^ _Right
        return _CSTD powl(_Left, _Right);
    }

    static _Ty sin(_Ty _Left) { // return sin(_Left)
        return _CSTD sinl(_Left);
    }

    static _Ty sqrt(_Ty _Left) { // return sqrt(_Left)
        return _CSTD sqrtl(_Left);
    }

    static _Ty tan(_Ty _Left) { // return tan(_Left)
        return _CSTD tanl(_Left);
    }

    static _Ty hypot(_Ty _Left, _Ty _Right) {
        return _CSTD hypotl(_Left, _Right);
    }
};

// CLASS _Ctraits<double>
template <>
class _Ctraits<double> { // complex traits for double
public:
    using _Ty = double;

    static _Ty _Flt_eps() { // get epsilon
        return DBL_EPSILON;
    }

    static _Ty _Flt_max() { // get max
        return DBL_MAX;
    }

    static _Ty _Cosh(_Ty _Left, _Ty _Right) { // return cosh(_Left) * _Right
        return _CSTD _Cosh(_Left, _Right);
    }

    static short _Exp(_Ty* _Pleft, _Ty _Right, short _Exponent) { // compute exp(*_Pleft) * _Right * 2 ^ _Exponent
        return _CSTD _Exp(_Pleft, _Right, _Exponent);
    }

    static _Ty _Infv() { // return infinity
        return numeric_limits<double>::infinity();
    }

    static bool _Isinf(_Ty _Left) { // test for infinity
        return _CSTD _Dtest(&_Left) == _INFCODE;
    }

    static bool _Isnan(_Ty _Left) { // test for NaN
        return _CSTD _Dtest(&_Left) == _NANCODE;
    }

    static _Ty _Nanv() { // return NaN
        return numeric_limits<double>::quiet_NaN();
    }

    static _Ty _Sinh(_Ty _Left, _Ty _Right) { // return sinh(_Left) * _Right
        return _CSTD _Sinh(_Left, _Right);
    }

    static _Ty asinh(_Ty _Left) { // return asinh(_Left)
        if (_Isnan(_Left) || _Isinf(_Left) || _Left == 0) {
            return 0;
        } else { // _Left finite nonzero
            const bool _Neg = _Left < 0;
            _Ty _Ans;

            if (_Neg) {
                _Left = -_Left;
            }

            if (_Left < 2 / _Flt_eps()) {
                _Ans = log1p(_Left + _Left * _Left / (1 + sqrt(_Left * _Left + 1)));
            } else {
                _Ans = log(_Left) // _Left big, compute log(_Left+_Left)
                       + (_Ty) 0.69314718055994530941723212145817658L;
            }

            return _Neg ? -_Ans : _Ans;
        }
    }

    static _Ty atan2(_Ty _Yval, _Ty _Xval) { // return atan(_Yval / _Xval)
        return _CSTD atan2(_Yval, _Xval);
    }

    static _Ty cos(_Ty _Left) { // return cos(_Left)
        return _CSTD cos(_Left);
    }

    static _Ty exp(_Ty _Left) { // return exp(_Left)
        return _CSTD exp(_Left);
    }

    static _Ty ldexp(_Ty _Left, int _Exponent) { // return _Left * 2 ^ _Exponent
        return _CSTD ldexp(_Left, _Exponent);
    }

    static _Ty log(_Ty _Left) { // return log(_Left)
        return _CSTD log(_Left);
    }

    static _Ty log1p(_Ty _Left) { // return log(1 + _Left)
        if (_Isnan(_Left) || _Left == 0 || (_Isinf(_Left) && 0 < _Left)) {
            return _Left;
        } else if (_Left < -1) {
            return _Nanv();
        } else if (_Left == -1) {
            return -_Infv();
        } else if (_Left == 0) {
            return _Left;
        } else { // compute log(1 + _Left) with fixup for small _Left
            _Ty _Leftp1 = 1 + _Left;
            return log(_Leftp1) - ((_Leftp1 - 1) - _Left) / _Leftp1;
        }
    }

    static _Ty pow(_Ty _Left, _Ty _Right) { // return _Left ^ _Right
        return _CSTD pow(_Left, _Right);
    }

    static _Ty sin(_Ty _Left) { // return sin(_Left)
        return _CSTD sin(_Left);
    }

    static _Ty sqrt(_Ty _Left) { // return sqrt(_Left)
        return _CSTD sqrt(_Left);
    }

    static _Ty tan(_Ty _Left) { // return tan(_Left)
        return _CSTD tan(_Left);
    }

    static _Ty hypot(_Ty _Left, _Ty _Right) {
        return _CSTD hypot(_Left, _Right);
    }
};

// CLASS _Ctraits<float>
template <>
class _Ctraits<float> { // complex traits for float
public:
    using _Ty = float;

    static _Ty _Flt_eps() { // get epsilon
        return FLT_EPSILON;
    }

    static _Ty _Flt_max() { // get max
        return FLT_MAX;
    }

    static _Ty _Cosh(_Ty _Left, _Ty _Right) { // return cosh(_Left) * _Right
        return _CSTD _FCosh(_Left, _Right);
    }

    static short _Exp(_Ty* _Pleft, _Ty _Right, short _Exponent) { // compute exp(*_Pleft) * _Right * 2 ^ _Exponent
        return _CSTD _FExp(_Pleft, _Right, _Exponent);
    }

    static _Ty _Infv() { // return infinity
        return numeric_limits<float>::infinity();
    }

    static bool _Isinf(_Ty _Left) { // test for infinity
        return _CSTD _FDtest(&_Left) == _INFCODE;
    }

    static bool _Isnan(_Ty _Left) { // test for NaN
        return _CSTD _FDtest(&_Left) == _NANCODE;
    }

    static _Ty _Nanv() { // return NaN
        return numeric_limits<float>::quiet_NaN();
    }

    static _Ty _Sinh(_Ty _Left, _Ty _Right) { // return sinh(_Left) * _Right
        return _CSTD _FSinh(_Left, _Right);
    }

    static _Ty asinh(_Ty _Left) { // return asinh(_Left)
        constexpr _Ty _Ln2 = 0.69314718055994530941723212145817658F;

        const bool _Neg = _Left < 0;
        _Ty _Ans;

        if (_Neg) {
            _Left = -_Left;
        }

        if (_Left < 2 / _Flt_eps()) {
            _Ans = log1p(_Left + _Left * _Left / (1 + sqrt(_Left * _Left + 1)));
        } else {
            _Ans = log(_Left) + _Ln2;
        }

        return _Neg ? -_Ans : _Ans;
    }

    static _Ty atan2(_Ty _Yval, _Ty _Xval) { // return atan(_Yval / _Xval)
        return _CSTD atan2f(_Yval, _Xval);
    }

    static _Ty cos(_Ty _Left) { // return cos(_Left)
        return _CSTD cosf(_Left);
    }

    static _Ty exp(_Ty _Left) { // return exp(_Left)
        return _CSTD expf(_Left);
    }

    static _Ty ldexp(_Ty _Left, int _Exponent) { // return _Left * 2 ^ _Exponent
        return _CSTD ldexpf(_Left, _Exponent);
    }

    static _Ty log(_Ty _Left) { // return log(_Left)
        return _CSTD logf(_Left);
    }

    static _Ty log1p(_Ty _Left) { // return log(1 + _Left)
        if (_Left < -1) {
            return _Nanv();
        } else if (_Left == 0) {
            return _Left;
        } else { // compute log(1 + _Left) with fixup for small _Left
            _Ty _Leftp1 = 1 + _Left;
            return log(_Leftp1) - ((_Leftp1 - 1) - _Left) / _Leftp1;
        }
    }

    static _Ty pow(_Ty _Left, _Ty _Right) { // return _Left ^ _Right
        return _CSTD powf(_Left, _Right);
    }

    static _Ty sin(_Ty _Left) { // return sin(_Left)
        return _CSTD sinf(_Left);
    }

    static _Ty sqrt(_Ty _Left) { // return sqrt(_Left)
        return _CSTD sqrtf(_Left);
    }

    static _Ty tan(_Ty _Left) { // return tan(_Left)
        return _CSTD tanf(_Left);
    }

    static _Ty hypot(_Ty _Left, _Ty _Right) {
        return _CSTD hypotf(_Left, _Right);
    }
};

// STRUCT TEMPLATE _Complex_value
template <class _Ty>
struct _Complex_value { // templatized complex value
    enum { _Re = 0, _Im = 1 };
    _Ty _Val[2];
};

// CLASS TEMPLATE _Complex_base
template <class _Ty,
    class _Valbase>
class _Complex_base : public _Valbase { // base for all complex types
public:
    using _Myctraits = _Ctraits<_Ty>;
    using value_type = _Ty;

    constexpr _Complex_base(const _Ty& _Realval, const _Ty& _Imagval)
        : _Valbase{{_Realval, _Imagval}} { // construct from components of same type
    }

    _Ty real(const _Ty& _Right) { // set real component
        return this->_Val[_RE] = _Right;
    }

    _Ty imag(const _Ty& _Right) { // set imaginary component
        return this->_Val[_IM] = _Right;
    }

    _NODISCARD constexpr _Ty real() const { // return real component
        return this->_Val[_RE];
    }

    _NODISCARD constexpr _Ty imag() const { // return imaginary component
        return this->_Val[_IM];
    }

protected:
    template <class _Other>
    inline void _Add(const complex<_Other>& _Right) { // add other complex
        this->_Val[_RE] = this->_Val[_RE] + (_Ty) _Right.real();
        this->_Val[_IM] = this->_Val[_IM] + (_Ty) _Right.imag();
    }

    template <class _Other>
    inline void _Sub(const complex<_Other>& _Right) { // subtract other complex
        this->_Val[_RE] = this->_Val[_RE] - (_Ty) _Right.real();
        this->_Val[_IM] = this->_Val[_IM] - (_Ty) _Right.imag();
    }

    template <class _Other>
    inline void _Mul(const complex<_Other>& _Right) { // multiply by other complex
        _Ty _Rightreal = (_Ty) _Right.real();
        _Ty _Rightimag = (_Ty) _Right.imag();

        _Ty _Tmp        = this->_Val[_RE] * _Rightreal - this->_Val[_IM] * _Rightimag;
        this->_Val[_IM] = this->_Val[_RE] * _Rightimag + this->_Val[_IM] * _Rightreal;
        this->_Val[_RE] = _Tmp;
    }

    template <class _Other>
    inline void _Div(const complex<_Other>& _Right) { // divide by other complex
        using _Myctraits = _Ctraits<_Ty>;

        _Ty _Rightreal = (_Ty) _Right.real();
        _Ty _Rightimag = (_Ty) _Right.imag();

        if (_Myctraits::_Isnan(_Rightreal) || _Myctraits::_Isnan(_Rightimag)) { // set NaN result
            this->_Val[_RE] = _Myctraits::_Nanv();
            this->_Val[_IM] = this->_Val[_RE];
        } else if ((_Rightimag < 0 ? -_Rightimag : +_Rightimag)
                   < (_Rightreal < 0 ? -_Rightreal : +_Rightreal)) { // |_Right.imag()| < |_Right.real()|
            _Ty _Wr = _Rightimag / _Rightreal;
            _Ty _Wd = _Rightreal + _Wr * _Rightimag;

            if (_Myctraits::_Isnan(_Wd) || _Wd == 0) { // set NaN result
                this->_Val[_RE] = _Myctraits::_Nanv();
                this->_Val[_IM] = this->_Val[_RE];
            } else { // compute representable result
                _Ty _Tmp        = (this->_Val[_RE] + this->_Val[_IM] * _Wr) / _Wd;
                this->_Val[_IM] = (this->_Val[_IM] - this->_Val[_RE] * _Wr) / _Wd;
                this->_Val[_RE] = _Tmp;
            }
        } else if (_Rightimag == 0) { // set NaN result
            this->_Val[_RE] = _Myctraits::_Nanv();
            this->_Val[_IM] = this->_Val[_RE];
        } else { // 0 < |_Right.real()| <= |_Right.imag()|
            _Ty _Wr = _Rightreal / _Rightimag;
            _Ty _Wd = _Rightimag + _Wr * _Rightreal;

            if (_Myctraits::_Isnan(_Wd) || _Wd == 0) { // set NaN result
                this->_Val[_RE] = _Myctraits::_Nanv();
                this->_Val[_IM] = this->_Val[_RE];
            } else { // compute representable result
                _Ty _Tmp        = (this->_Val[_RE] * _Wr + this->_Val[_IM]) / _Wd;
                this->_Val[_IM] = (this->_Val[_IM] * _Wr - this->_Val[_RE]) / _Wd;
                this->_Val[_RE] = _Tmp;
            }
        }
    }
};

// CLASS complex<float>
template <>
class complex<float> : public _Complex_base<float, _Fcomplex_value> { // complex with float components
public:
    using _Ty = float;

    constexpr explicit complex(const complex<double>&); // defined below
    constexpr explicit complex(const complex<long double>&); // defined below

    constexpr complex(const _Ty& _Realval = 0, const _Ty& _Imagval = 0)
        : _Complex_base<float, _Fcomplex_value>(_Realval, _Imagval) { // construct from float components
    }

    constexpr complex(const _Fcomplex_value& _Right)
        : _Complex_base<float, _Fcomplex_value>(_Right._Val[_RE],
              _Right._Val[_IM]) { // construct from float complex value
    }

    constexpr complex(const _Dcomplex_value& _Right)
        : _Complex_base<float, _Fcomplex_value>(static_cast<float>(_Right._Val[_RE]),
              static_cast<float>(_Right._Val[_IM])) { // construct from double complex value
    }

    constexpr complex(const _Lcomplex_value& _Right)
        : _Complex_base<float, _Fcomplex_value>(static_cast<float>(_Right._Val[_RE]),
              static_cast<float>(_Right._Val[_IM])) { // construct from long double complex value
    }

    complex<_Ty>& operator=(const _Ty& _Right) { // assign real

        _Val[_RE] = _Right;
        _Val[_IM] = 0;
        return *this;
    }

    complex& operator+=(const _Ty& _Right) { // add real
        _Val[_RE] = _Val[_RE] + _Right;
        return *this;
    }

    complex& operator-=(const _Ty& _Right) { // subtract real
        _Val[_RE] = _Val[_RE] - _Right;
        return *this;
    }

    complex& operator*=(const _Ty& _Right) { // multiply by real
        _Val[_RE] = _Val[_RE] * _Right;
        _Val[_IM] = _Val[_IM] * _Right;
        return *this;
    }

    complex& operator/=(const _Ty& _Right) { // divide by real
        _Val[_RE] = _Val[_RE] / _Right;
        _Val[_IM] = _Val[_IM] / _Right;
        return *this;
    }

    complex& operator+=(const complex& _Right) { // add other complex
        this->_Add(_Right);
        return *this;
    }

    complex& operator-=(const complex& _Right) { // subtract other complex
        this->_Sub(_Right);
        return *this;
    }

    complex& operator*=(const complex& _Right) { // multiply by other complex
        this->_Mul(_Right);
        return *this;
    }

    complex& operator/=(const complex& _Right) { // divide by other complex
        this->_Div(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator=(const complex<_Other>& _Right) { // assign another complex

        _Val[_RE] = (_Ty) _Right._Val[_RE];
        _Val[_IM] = (_Ty) _Right._Val[_IM];
        return *this;
    }

    template <class _Other>
    inline complex& operator+=(const complex<_Other>& _Right) { // add other complex
        this->_Add(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator-=(const complex<_Other>& _Right) { // subtract other complex
        this->_Sub(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator*=(const complex<_Other>& _Right) { // multiply by other complex
        this->_Mul(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator/=(const complex<_Other>& _Right) { // divide by other complex
        this->_Div(_Right);
        return *this;
    }
};

// CLASS complex<double>
template <>
class complex<double> : public _Complex_base<double, _Dcomplex_value> { // complex with double components
public:
    using _Ty = double;

    constexpr complex(const complex<float>&); // defined below
    constexpr explicit complex(const complex<long double>&); // defined below

    constexpr complex(const _Ty& _Realval = 0, const _Ty& _Imagval = 0)
        : _Complex_base<double, _Dcomplex_value>(_Realval, _Imagval) { // construct from double components
    }

    constexpr complex(const _Dcomplex_value& _Right)
        : _Complex_base<double, _Dcomplex_value>(_Right._Val[_RE],
              _Right._Val[_IM]) { // construct from double complex value
    }

    constexpr complex(const _Lcomplex_value& _Right)
        : _Complex_base<double, _Dcomplex_value>(static_cast<double>(_Right._Val[_RE]),
              static_cast<double>(_Right._Val[_IM])) { // construct from long double complex value
    }

    complex<_Ty>& operator=(const _Ty& _Right) { // assign real

        _Val[_RE] = _Right;
        _Val[_IM] = 0;
        return *this;
    }

    complex& operator+=(const _Ty& _Right) { // add real
        _Val[_RE] = _Val[_RE] + _Right;
        return *this;
    }

    complex& operator-=(const _Ty& _Right) { // subtract real
        _Val[_RE] = _Val[_RE] - _Right;
        return *this;
    }

    complex& operator*=(const _Ty& _Right) { // multiply by real
        _Val[_RE] = _Val[_RE] * _Right;
        _Val[_IM] = _Val[_IM] * _Right;
        return *this;
    }

    complex& operator/=(const _Ty& _Right) { // divide by real
        _Val[_RE] = _Val[_RE] / _Right;
        _Val[_IM] = _Val[_IM] / _Right;
        return *this;
    }

    complex& operator+=(const complex& _Right) { // add other complex
        this->_Add(_Right);
        return *this;
    }

    complex& operator-=(const complex& _Right) { // subtract other complex
        this->_Sub(_Right);
        return *this;
    }

    complex& operator*=(const complex& _Right) { // multiply by other complex
        this->_Mul(_Right);
        return *this;
    }

    complex& operator/=(const complex& _Right) { // divide by other complex
        this->_Div(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator=(const complex<_Other>& _Right) { // assign another complex

        _Val[_RE] = (_Ty) _Right._Val[_RE];
        _Val[_IM] = (_Ty) _Right._Val[_IM];
        return *this;
    }

    template <class _Other>
    inline complex& operator+=(const complex<_Other>& _Right) { // add other complex
        this->_Add(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator-=(const complex<_Other>& _Right) { // subtract other complex
        this->_Sub(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator*=(const complex<_Other>& _Right) { // multiply by other complex
        this->_Mul(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator/=(const complex<_Other>& _Right) { // divide by other complex
        this->_Div(_Right);
        return *this;
    }
};

// CLASS complex<long double>
template <>
class complex<long double> : public _Complex_base<long double, _Lcomplex_value> { // complex with long double components
public:
    using _Ty = long double;

    constexpr complex(const complex<float>&); // defined below
    constexpr complex(const complex<double>&); // defined below

    constexpr complex(const _Ty& _Realval = 0, const _Ty& _Imagval = 0)
        : _Complex_base<long double, _Lcomplex_value>(_Realval, _Imagval) { // construct from long double components
    }

    constexpr complex(const _Lcomplex_value& _Right)
        : _Complex_base<long double, _Lcomplex_value>(_Right._Val[_RE],
              _Right._Val[_IM]) { // construct from long double complex value
    }

    complex<_Ty>& operator=(const _Ty& _Right) { // assign real

        _Val[_RE] = _Right;
        _Val[_IM] = 0;
        return *this;
    }

    complex& operator+=(const _Ty& _Right) { // add real
        _Val[_RE] = _Val[_RE] + _Right;
        return *this;
    }

    complex& operator-=(const _Ty& _Right) { // subtract real
        _Val[_RE] = _Val[_RE] - _Right;
        return *this;
    }

    complex& operator*=(const _Ty& _Right) { // multiply by real
        _Val[_RE] = _Val[_RE] * _Right;
        _Val[_IM] = _Val[_IM] * _Right;
        return *this;
    }

    complex& operator/=(const _Ty& _Right) { // divide by real
        _Val[_RE] = _Val[_RE] / _Right;
        _Val[_IM] = _Val[_IM] / _Right;
        return *this;
    }

    complex& operator+=(const complex& _Right) { // add other complex
        this->_Add(_Right);
        return *this;
    }

    complex& operator-=(const complex& _Right) { // subtract other complex
        this->_Sub(_Right);
        return *this;
    }

    complex& operator*=(const complex& _Right) { // multiply by other complex
        this->_Mul(_Right);
        return *this;
    }

    complex& operator/=(const complex& _Right) { // divide by other complex
        this->_Div(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator=(const complex<_Other>& _Right) { // assign another complex

        _Val[_RE] = (_Ty) _Right._Val[_RE];
        _Val[_IM] = (_Ty) _Right._Val[_IM];
        return *this;
    }

    template <class _Other>
    inline complex& operator+=(const complex<_Other>& _Right) { // add other complex
        this->_Add(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator-=(const complex<_Other>& _Right) { // subtract other complex
        this->_Sub(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator*=(const complex<_Other>& _Right) { // multiply by other complex
        this->_Mul(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator/=(const complex<_Other>& _Right) { // divide by other complex
        this->_Div(_Right);
        return *this;
    }
};

// CONSTRUCTORS FOR complex SPECIALIZATIONS
constexpr complex<float>::complex(const complex<double>& _Right)
    : _Complex_base<float, _Fcomplex_value>(
          (_Ty) _Right.real(), (_Ty) _Right.imag()) { // construct complex<float> from complex<double>
}

constexpr complex<float>::complex(const complex<long double>& _Right)
    : _Complex_base<float, _Fcomplex_value>(
          (_Ty) _Right.real(), (_Ty) _Right.imag()) { // construct complex<float> from complex<long double>
}

constexpr complex<double>::complex(const complex<float>& _Right)
    : _Complex_base<double, _Dcomplex_value>(
          (_Ty) _Right.real(), (_Ty) _Right.imag()) { // construct complex<double> from complex<float>
}

constexpr complex<double>::complex(const complex<long double>& _Right)
    : _Complex_base<double, _Dcomplex_value>(
          (_Ty) _Right.real(), (_Ty) _Right.imag()) { // construct complex<double> from complex<long double>
}

constexpr complex<long double>::complex(const complex<float>& _Right)
    : _Complex_base<long double, _Lcomplex_value>(
          (_Ty) _Right.real(), (_Ty) _Right.imag()) { // construct complex<long double> from complex<float>
}

constexpr complex<long double>::complex(const complex<double>& _Right)
    : _Complex_base<long double, _Lcomplex_value>(
          (_Ty) _Right.real(), (_Ty) _Right.imag()) { // construct complex<long double> from complex<double>
}

// CLASS TEMPLATE complex
template <class _Ty>
class complex : public _Complex_base<_Ty, _Complex_value<_Ty>> { // complex with _Ty components
public:
    using _Mybase = _Complex_base<_Ty, _Complex_value<_Ty>>;

    constexpr complex(const _Ty& _Realval = _Ty(), const _Ty& _Imagval = _Ty())
        : _Mybase(_Realval, _Imagval) { // construct from components of same type
    }

    complex& operator=(const _Ty& _Right) { // assign real

        this->_Val[_RE] = _Right;
        this->_Val[_IM] = _Ty();
        return *this;
    }

    template <class _Other>
    constexpr complex(const complex<_Other>& _Right)
        : _Mybase((_Ty) _Right.real(), (_Ty) _Right.imag()) { // construct from other complex type
    }

    template <class _Other>
    complex& operator=(const complex<_Other>& _Right) { // assign other complex type

        this->_Val[_RE] = (_Ty) _Right.real();
        this->_Val[_IM] = (_Ty) _Right.imag();
        return *this;
    }

    complex& operator+=(const _Ty& _Right) { // add real
        this->_Val[_RE] = this->_Val[_RE] + _Right;
        return *this;
    }

    complex& operator-=(const _Ty& _Right) { // subtract real
        this->_Val[_RE] = this->_Val[_RE] - _Right;
        return *this;
    }

    complex& operator*=(const _Ty& _Right) { // multiply by real
        this->_Val[_RE] = this->_Val[_RE] * _Right;
        this->_Val[_IM] = this->_Val[_IM] * _Right;
        return *this;
    }

    complex& operator/=(const _Ty& _Right) { // divide by real
        this->_Val[_RE] = this->_Val[_RE] / _Right;
        this->_Val[_IM] = this->_Val[_IM] / _Right;
        return *this;
    }

    complex& operator+=(const complex& _Right) { // add other complex
        this->_Add(_Right);
        return *this;
    }

    complex& operator-=(const complex& _Right) { // subtract other complex
        this->_Sub(_Right);
        return *this;
    }

    complex& operator*=(const complex& _Right) { // multiply by other complex
        this->_Mul(_Right);
        return *this;
    }

    complex& operator/=(const complex& _Right) { // divide by other complex
        this->_Div(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator+=(const complex<_Other>& _Right) { // add other complex
        this->_Add(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator-=(const complex<_Other>& _Right) { // subtract other complex
        this->_Sub(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator*=(const complex<_Other>& _Right) { // multiply by other complex
        this->_Mul(_Right);
        return *this;
    }

    template <class _Other>
    inline complex& operator/=(const complex<_Other>& _Right) { // divide by other complex
        this->_Div(_Right);
        return *this;
    }
};

// FUNCTION TEMPLATE operator+
template <class _Ty>
_NODISCARD inline complex<_Ty> operator+(
    const complex<_Ty>& _Left, const complex<_Ty>& _Right) { // add complex to complex
    complex<_Ty> _Tmp(_Left);
    _Tmp += _Right;
    return _Tmp;
}

template <class _Ty>
_NODISCARD inline complex<_Ty> operator+(const complex<_Ty>& _Left, const _Ty& _Right) { // add real to complex
    complex<_Ty> _Tmp(_Left);
    _Tmp.real(_Tmp.real() + _Right);
    return _Tmp;
}

template <class _Ty>
_NODISCARD inline complex<_Ty> operator+(const _Ty& _Left, const complex<_Ty>& _Right) { // add complex to real
    complex<_Ty> _Tmp(_Left);
    _Tmp += _Right;
    return _Tmp;
}

// FUNCTION TEMPLATE operator-
template <class _Ty>
_NODISCARD inline complex<_Ty> operator-(
    const complex<_Ty>& _Left, const complex<_Ty>& _Right) { // subtract complex from complex
    complex<_Ty> _Tmp(_Left);
    _Tmp -= _Right;
    return _Tmp;
}

template <class _Ty>
_NODISCARD inline complex<_Ty> operator-(const complex<_Ty>& _Left, const _Ty& _Right) { // subtract real from complex
    complex<_Ty> _Tmp(_Left);
    _Tmp.real(_Tmp.real() - _Right);
    return _Tmp;
}

template <class _Ty>
_NODISCARD inline complex<_Ty> operator-(const _Ty& _Left, const complex<_Ty>& _Right) { // subtract complex from real
    complex<_Ty> _Tmp(_Left);
    _Tmp -= _Right;
    return _Tmp;
}

// FUNCTION TEMPLATE operator*
template <class _Ty>
_NODISCARD inline complex<_Ty> operator*(
    const complex<_Ty>& _Left, const complex<_Ty>& _Right) { // multiply complex by complex
    complex<_Ty> _Tmp(_Left);
    _Tmp *= _Right;
    return _Tmp;
}

template <class _Ty>
_NODISCARD inline complex<_Ty> operator*(const complex<_Ty>& _Left, const _Ty& _Right) { // multiply complex by real
    complex<_Ty> _Tmp(_Left);
    _Tmp.real(_Tmp.real() * _Right);
    _Tmp.imag(_Tmp.imag() * _Right);
    return _Tmp;
}

template <class _Ty>
_NODISCARD inline complex<_Ty> operator*(const _Ty& _Left, const complex<_Ty>& _Right) { // multiply real by complex
    complex<_Ty> _Tmp(_Left);
    _Tmp *= _Right;
    return _Tmp;
}

// FUNCTION TEMPLATE operator/
template <class _Ty>
_NODISCARD inline complex<_Ty> operator/(
    const complex<_Ty>& _Left, const complex<_Ty>& _Right) { // divide complex by complex
    complex<_Ty> _Tmp(_Left);
    _Tmp /= _Right;
    return _Tmp;
}

template <class _Ty>
_NODISCARD inline complex<_Ty> operator/(const complex<_Ty>& _Left, const _Ty& _Right) { // divide complex by real
    complex<_Ty> _Tmp(_Left);
    _Tmp.real(_Tmp.real() / _Right);
    _Tmp.imag(_Tmp.imag() / _Right);
    return _Tmp;
}

template <class _Ty>
_NODISCARD inline complex<_Ty> operator/(const _Ty& _Left, const complex<_Ty>& _Right) { // divide real by complex
    complex<_Ty> _Tmp(_Left);
    _Tmp /= _Right;
    return _Tmp;
}

// FUNCTION TEMPLATE UNARY operator+
template <class _Ty>
_NODISCARD inline complex<_Ty> operator+(const complex<_Ty>& _Left) { // return +complex
    return _Left;
}

// FUNCTION TEMPLATE UNARY operator-
template <class _Ty>
_NODISCARD inline complex<_Ty> operator-(const complex<_Ty>& _Left) { // return -complex
    return complex<_Ty>(-_Left.real(), -_Left.imag());
}

// FUNCTION TEMPLATE operator==
template <class _Ty>
_NODISCARD constexpr bool operator==(
    const complex<_Ty>& _Left, const complex<_Ty>& _Right) { // test complex equal to complex
    return _Left.real() == _Right.real() && _Left.imag() == _Right.imag();
}

template <class _Ty>
_NODISCARD constexpr bool operator==(const complex<_Ty>& _Left, const _Ty& _Right) { // test real equal to complex
    return _Left.real() == _Right && _Left.imag() == 0;
}

template <class _Ty>
_NODISCARD constexpr bool operator==(const _Ty& _Left, const complex<_Ty>& _Right) { // test complex equal to real
    return _Left == _Right.real() && 0 == _Right.imag();
}

// FUNCTION TEMPLATE operator!=
template <class _Ty>
_NODISCARD constexpr bool operator!=(
    const complex<_Ty>& _Left, const complex<_Ty>& _Right) { // test complex not equal to complex
    return !(_Left == _Right);
}

template <class _Ty>
_NODISCARD constexpr bool operator!=(const complex<_Ty>& _Left, const _Ty& _Right) { // test real not equal to complex
    return !(_Left == _Right);
}

template <class _Ty>
_NODISCARD constexpr bool operator!=(const _Ty& _Left, const complex<_Ty>& _Right) { // test complex not equal to real
    return !(_Left == _Right);
}

// FUNCTION TEMPLATE imag
template <class _Ty>
_NODISCARD constexpr _Ty imag(const complex<_Ty>& _Left) { // return imaginary component
    return _Left.imag();
}

// FUNCTION TEMPLATE real
template <class _Ty>
_NODISCARD constexpr _Ty real(const complex<_Ty>& _Left) { // return real component
    return _Left.real();
}

template <class _Ty>
_NODISCARD inline complex<_Ty> sqrt(const complex<_Ty>& _Left);

// FUNCTION TEMPLATE abs
template <class _Ty>
_NODISCARD inline _Ty abs(const complex<_Ty>& _Left) { // return |complex| as real
    return _Ctraits<_Ty>::hypot(_Left.real(), _Left.imag());
}

// FUNCTION TEMPLATE acos
template <class _Ty>
_NODISCARD inline complex<_Ty> acos(const complex<_Ty>& _Left) { // return acos
    const _Ty _Arcbig = (_Ty) 0.25L * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max());
    constexpr _Ty _Pi = (_Ty) 3.1415926535897932384626433832795029L;

    const _Ty _Re = real(_Left);
    const _Ty _Im = imag(_Left);
    _Ty _Ux;
    _Ty _Vx;

    if (_Ctraits<_Ty>::_Isnan(_Re) || _Ctraits<_Ty>::_Isnan(_Im)) { // at least one NaN
        _Ux = _Ctraits<_Ty>::_Nanv();
        _Vx = _Ux;
    } else if (_Ctraits<_Ty>::_Isinf(_Re)) { // (+/-Inf, not NaN)
        if (_Ctraits<_Ty>::_Isinf(_Im)) {
            if (_Re < 0) {
                _Ux = (_Ty) 0.75 * _Pi; // (-Inf, +/-Inf)
            } else {
                _Ux = (_Ty) 0.25 * _Pi; // (+Inf, +/-Inf)
            }
        } else if (_Re < 0) {
            _Ux = _Pi; // (-Inf, finite)
        } else {
            _Ux = 0; // (+Inf, finite)
        }
        _Vx = -_Ctraits<_Ty>::_Infv();
        if (_Im < 0) {
            _Vx = -_Vx;
        }
    } else if (_Ctraits<_Ty>::_Isinf(_Im)) { // (finite, finite)
        _Ux = (_Ty) 0.50 * _Pi; // (finite, +/-Inf)
        _Vx = -_Im;
    } else { // (finite, finite)
        const complex<_Ty> _Wx = sqrt(complex<_Ty>(1 + _Re, -_Im));
        const complex<_Ty> _Zx = sqrt(complex<_Ty>(1 - _Re, -_Im));
        const _Ty _Wr          = real(_Wx);
        const _Ty _Wi          = imag(_Wx);
        const _Ty _Zr          = real(_Zx);
        const _Ty _Zi          = imag(_Zx);
        _Ty _Alfa, _Beta;

        _Ux = 2 * _Ctraits<_Ty>::atan2(_Zr, _Wr);

        if (_Arcbig < _Wr) { // real parts large
            _Alfa = _Wr;
            _Beta = _Zi + _Wi * (_Zr / _Alfa);
        } else if (_Arcbig < _Wi) { // imag parts large
            _Alfa = _Wi;
            _Beta = _Wr * (_Zi / _Alfa) + _Zr;
        } else if (_Wi < -_Arcbig) { // imag part of w large negative
            _Alfa = -_Wi;
            _Beta = _Wr * (_Zi / _Alfa) + _Zr;
        } else { // shouldn't overflow
            _Alfa = 0;
            _Beta = _Wr * _Zi + _Wi * _Zr; // Im(w * z)
        }

        _Vx = _Ctraits<_Ty>::asinh(_Beta);
        if (_Alfa != 0) {
            if (0 <= _Ux) {
                _Vx += _Ctraits<_Ty>::log(_Alfa);
            } else {
                _Vx -= _Ctraits<_Ty>::log(_Alfa); // asinh(a*b) = asinh(a)+log(b)
            }
        }
    }
    return complex<_Ty>(_Ux, _Vx);
}

// FUNCTION TEMPLATE acosh
template <class _Ty>
_NODISCARD inline complex<_Ty> acosh(const complex<_Ty>& _Left) { // return acosh
    const _Ty _Arcbig = (_Ty) 0.25L * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max());
    constexpr _Ty _Pi = (_Ty) 3.1415926535897932384626433832795029L;

    const _Ty _Re = real(_Left);
    _Ty _Im       = imag(_Left);
    _Ty _Ux;
    _Ty _Vx;

    if (_Ctraits<_Ty>::_Isnan(_Re) || _Ctraits<_Ty>::_Isnan(_Im)) { // at least one NaN
        _Ux = _Ctraits<_Ty>::_Nanv();
        _Vx = _Ux;
    } else if (_Ctraits<_Ty>::_Isinf(_Re)) { // (+/-Inf, not NaN)
        _Ux = _Ctraits<_Ty>::_Infv();

        if (_Ctraits<_Ty>::_Isinf(_Im)) {
            if (_Re < 0) {
                _Vx = (_Ty) 0.75 * _Pi; // (-Inf, +/-Inf)
            } else {
                _Vx = (_Ty) 0.25 * _Pi; // (+Inf, +/-Inf)
            }
        } else if (_Re < 0) {
            _Vx = _Pi; // (-Inf, finite)
        } else {
            _Vx = 0; // (+Inf, finite)
        }

        if (_Im < 0) {
            _Vx = -_Vx;
        }
    } else if (_Ctraits<_Ty>::_Isinf(_Im)) { // (finite, +/-Inf)
        _Ux = _Ctraits<_Ty>::_Infv();
        _Vx = _Im < 0 ? -(_Ty) 0.50 * _Pi : (_Ty) 0.50 * _Pi;
    } else { // (finite, finite)
        const complex<_Ty> _Wx = sqrt(complex<_Ty>(_Re - 1, -_Im));
        const complex<_Ty> _Zx = sqrt(complex<_Ty>(_Re + 1, _Im));
        const _Ty _Wr          = real(_Wx);
        const _Ty _Wi          = imag(_Wx);
        const _Ty _Zr          = real(_Zx);
        const _Ty _Zi          = imag(_Zx);
        _Ty _Alfa, _Beta;

        if (_Arcbig < _Wr) { // real parts large
            _Alfa = _Wr;
            _Beta = _Zr - _Wi * (_Zi / _Alfa);
        } else if (_Arcbig < _Wi) { // imag parts large
            _Alfa = _Wi;
            _Beta = _Wr * (_Zr / _Alfa) - _Zi;
        } else if (_Wi < -_Arcbig) { // imag part of w large negative
            _Alfa = -_Wi;
            _Beta = _Wr * (_Zr / _Alfa) - _Zi;
        } else { // shouldn't overflow
            _Alfa = 0;
            _Beta = _Wr * _Zr - _Wi * _Zi; // Re(w * z)
        }

        _Ux = _Ctraits<_Ty>::asinh(_Beta);
        if (_Alfa != 0) {
            if (0 <= _Ux) {
                _Ux += _Ctraits<_Ty>::log(_Alfa);
            } else {
                _Ux -= _Ctraits<_Ty>::log(_Alfa); // asinh(a*b) = asinh(a)+log(b)
            }
        }

        bool _Neg = true;
        if (_Im < 0) {
            _Im = -_Im;
        } else {
            _Neg = false;
        }

        _Vx = 2 * _Ctraits<_Ty>::atan2(imag(sqrt(complex<_Ty>(_Re - 1, _Im))), _Zr);
        if (_Neg) {
            _Vx = -_Vx;
        }
    }
    return complex<_Ty>(_Ux, _Vx);
}

// FUNCTION TEMPLATE asinh
template <class _Ty>
_NODISCARD inline complex<_Ty> asinh(const complex<_Ty>& _Left) { // return asinh
    const _Ty _Arcbig = (_Ty) 0.25L * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max());
    constexpr _Ty _Pi = (_Ty) 3.1415926535897932384626433832795029L;

    const _Ty _Re = real(_Left);
    _Ty _Im       = imag(_Left);
    _Ty _Ux;
    _Ty _Vx;

    if (_Ctraits<_Ty>::_Isnan(_Re) || _Ctraits<_Ty>::_Isnan(_Im)) { // at least one NaN/Inf
        _Ux = _Ctraits<_Ty>::_Nanv();
        _Vx = _Ux;
    } else if (_Ctraits<_Ty>::_Isinf(_Re)) { // (+/-Inf, not NaN)
        _Ux = _Ctraits<_Ty>::_Infv();

        if (_Ctraits<_Ty>::_Isinf(_Im)) { // (+/-Inf, +/-Inf)
            _Ux = _Re;
            _Vx = _Im < 0 ? -(_Ty) 0.25 * _Pi : (_Ty) 0.25 * _Pi;
        } else { // (+/-Inf, finite)
            _Ux = _Re;
            _Vx = _Im < 0 ? -(_Ty) 0 : (_Ty) 0;
        }
    } else if (_Ctraits<_Ty>::_Isinf(_Im)) { // (finite, +/-Inf)
        _Ux = _Im;
        _Vx = _Im < 0 ? -(_Ty) 0.50 * _Pi : (_Ty) 0.50 * _Pi;
    } else { // (finite, finite)
        const complex<_Ty> _Wx = sqrt(complex<_Ty>(1 - _Im, _Re));
        const complex<_Ty> _Zx = sqrt(complex<_Ty>(1 + _Im, -_Re));
        const _Ty _Wr          = real(_Wx);
        const _Ty _Wi          = imag(_Wx);
        const _Ty _Zr          = real(_Zx);
        const _Ty _Zi          = imag(_Zx);
        _Ty _Alfa, _Beta;

        if (_Arcbig < _Wr) { // real parts large
            _Alfa = _Wr;
            _Beta = _Wi * (_Zr / _Alfa) - _Zi;
        } else if (_Arcbig < _Wi) { // imag parts large
            _Alfa = _Wi;
            _Beta = _Zr - _Wr * (_Zi / _Alfa);
        } else if (_Wi < -_Arcbig) { // imag part of w large negative
            _Alfa = -_Wi;
            _Beta = _Zr - _Wr * (_Zi / _Alfa);
        } else { // shouldn't overflow
            _Alfa = 0;
            _Beta = _Wi * _Zr - _Wr * _Zi; // Im(w * conj(z))
        }

        _Ux = _Ctraits<_Ty>::asinh(_Beta);
        if (_Alfa != 0) {
            if (0 <= _Ux) {
                _Ux += _Ctraits<_Ty>::log(_Alfa);
            } else {
                _Ux -= _Ctraits<_Ty>::log(_Alfa); // asinh(a*b) = asinh(a)+log(b)
            }
        }

        _Vx = _Ctraits<_Ty>::atan2(_Im, real(_Wx * _Zx));
    }

    return complex<_Ty>(_Ux, _Vx);
}

// FUNCTION TEMPLATE asin
template <class _Ty>
_NODISCARD inline complex<_Ty> asin(const complex<_Ty>& _Left) { // return asin
    complex<_Ty> _Asinh = _STD asinh(complex<_Ty>(-imag(_Left), real(_Left)));

    return complex<_Ty>(imag(_Asinh), -real(_Asinh));
}

// FUNCTION TEMPLATE atanh
template <class _Ty>
_NODISCARD inline complex<_Ty> atanh(const complex<_Ty>& _Left) { // return atanh
    const _Ty _Arcbig    = (_Ty) 0.25L * _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::_Flt_max());
    constexpr _Ty _Piby2 = (_Ty) 1.5707963267948966192313216916397514L;

    _Ty _Re = real(_Left);
    _Ty _Im = imag(_Left);
    _Ty _Ux;
    _Ty _Vx;

    if (_Ctraits<_Ty>::_Isnan(_Re) || _Ctraits<_Ty>::_Isnan(_Im)) { // at least one NaN
        _Ux = _Ctraits<_Ty>::_Nanv();
        _Vx = _Ux;
    } else if (_Ctraits<_Ty>::_Isinf(_Re)) { // (+/-Inf, not NaN)
        _Ux = _Re < 0 ? -(_Ty) 0 : (_Ty) 0;
        _Vx = _Im < 0 ? -_Piby2 : _Piby2;
    } else { // (finite, not _NaN)
        _Ty _Magim = _Im < 0 ? -_Im : _Im;
        bool _Neg  = _Re < 0;

        if (_Neg) {
            _Re = -_Re;
        } else {
            _Im = -_Im;
        }

        if (_Arcbig < _Re) { // |re| is large
            _Ty _Fx = _Im / _Re;

            _Ux = 1 / _Re / (1 + _Fx * _Fx);
            _Vx = _Im < 0 ? -_Piby2 : _Piby2;
        } else if (_Arcbig < _Magim) { // |im| is large
            _Ty _Fx = _Re / _Im;

            _Ux = _Fx / _Im / (1 + _Fx * _Fx);
            _Vx = _Im < 0 ? -_Piby2 : _Piby2;
        } else if (_Re != 1) { // |re| is small
            _Ty _Refrom1 = 1 - _Re;
            _Ty _Imeps2  = _Magim * _Magim;

            _Ux = (_Ty) 0.25 * _Ctraits<_Ty>::log1p(4 * _Re / (_Refrom1 * _Refrom1 + _Imeps2));
            _Vx = (_Ty) 0.50 * _Ctraits<_Ty>::atan2(2 * _Im, _Refrom1 * (1 + _Re) - _Imeps2);
        } else if (_Im == 0) { // {+/-1, 0)
            _Ux = _Ctraits<_Ty>::_Infv();
            _Vx = _Im;
        } else { // {+/-1, nonzero)
            _Ux = _Ctraits<_Ty>::log(
                _Ctraits<_Ty>::sqrt(_Ctraits<_Ty>::sqrt(4 + _Im * _Im)) / _Ctraits<_Ty>::sqrt(_Magim));
            _Vx = (_Ty) 0.50 * (_Piby2 + _Ctraits<_Ty>::atan2(_Magim, 2));
            if (_Im < 0) {
                _Vx = -_Vx;
            }
        }

        if (_Neg) {
            _Ux = -_Ux;
        } else {
            _Vx = -_Vx;
        }
    }
    return complex<_Ty>(_Ux, _Vx);
}

// FUNCTION TEMPLATE atan
template <class _Ty>
_NODISCARD inline complex<_Ty> atan(const complex<_Ty>& _Left) { // return atan
    complex<_Ty> _Atanh = _STD atanh(complex<_Ty>(-imag(_Left), real(_Left)));

    return complex<_Ty>(imag(_Atanh), -real(_Atanh));
}

// FUNCTION TEMPLATE cosh
template <class _Ty>
_NODISCARD inline complex<_Ty> cosh(const complex<_Ty>& _Left) { // return cosh(complex)
    return complex<_Ty>(_Ctraits<_Ty>::_Cosh(real(_Left), _Ctraits<_Ty>::cos(imag(_Left))),
        _Ctraits<_Ty>::_Sinh(real(_Left), _Ctraits<_Ty>::sin(imag(_Left))));
}

// FUNCTION TEMPLATE exp
template <class _Ty>
_NODISCARD inline complex<_Ty> exp(const complex<_Ty>& _Left) { // return exp(complex)
    _Ty _Real(real(_Left)), _Imag(real(_Left));
    _Ctraits<_Ty>::_Exp(&_Real, _Ctraits<_Ty>::cos(imag(_Left)), 0);
    _Ctraits<_Ty>::_Exp(&_Imag, _Ctraits<_Ty>::sin(imag(_Left)), 0);
    return complex<_Ty>(_Real, _Imag);
}

// FUNCTION TEMPLATE _Fabs
template <class _Ty>
inline _Ty _Fabs(const complex<_Ty>& _Left, int* _Pexp) { // return magnitude and scale factor
    *_Pexp  = 0;
    _Ty _Av = real(_Left);
    _Ty _Bv = imag(_Left);

    if (_Ctraits<_Ty>::_Isinf(_Av) || _Ctraits<_Ty>::_Isinf(_Bv)) {
        return _Ctraits<_Ty>::_Infv(); // at least one component is INF
    } else if (_Ctraits<_Ty>::_Isnan(_Av)) {
        return _Av; // real component is NaN
    } else if (_Ctraits<_Ty>::_Isnan(_Bv)) {
        return _Bv; // imaginary component is NaN
    } else { // neither component is NaN or INF
        if (_Av < 0) {
            _Av = -_Av;
        }

        if (_Bv < 0) {
            _Bv = -_Bv;
        }

        if (_Av < _Bv) { // ensure that |_Bv| <= |_Av|
            _Ty _Tmp = _Av;
            _Av      = _Bv;
            _Bv      = _Tmp;
        }

        if (_Av == 0) {
            return _Av; // |0| == 0
        }

        if (1 <= _Av) {
            *_Pexp = 2;
            _Av    = _Av * (_Ty) 0.25;
            _Bv    = _Bv * (_Ty) 0.25;
        } else {
            *_Pexp = -2;
            _Av    = _Av * 4;
            _Bv    = _Bv * 4;
        }

        _Ty _Tmp = _Av - _Bv;
        if (_Tmp == _Av) {
            return _Av; // _Bv unimportant
        } else if (_Bv < _Tmp) { // use simple approximation
            const _Ty _Qv = _Av / _Bv;
            return _Av + _Bv / (_Qv + _Ctraits<_Ty>::sqrt(_Qv * _Qv + 1));
        } else { // use 1 1/2 precision to preserve bits
            constexpr _Ty _Root2            = (_Ty) 1.4142135623730950488016887242096981L;
            constexpr _Ty _Oneplusroot2high = (_Ty)(10125945.0 / 4194304.0); // exact if prec >= 24 bits
            constexpr _Ty _Oneplusroot2low  = (_Ty) 1.4341252375973918872420969807856967e-7L;

            const _Ty _Qv = _Tmp / _Bv;
            const _Ty _Rv = (_Qv + 2) * _Qv;
            const _Ty _Sv = _Rv / (_Root2 + _Ctraits<_Ty>::sqrt(_Rv + 2)) + _Oneplusroot2low + _Qv + _Oneplusroot2high;
            return _Av + _Bv / _Sv;
        }
    }
}

// FUNCTION TEMPLATE log
template <class _Ty>
_NODISCARD inline complex<_Ty> log(const complex<_Ty>& _Left) { // return log(complex)
    _Ty _Theta = _Ctraits<_Ty>::atan2(imag(_Left), real(_Left)); // get phase

    if (_Ctraits<_Ty>::_Isnan(_Theta)) {
        return complex<_Ty>(_Theta, _Theta); // real or imag is NaN
    } else { // use 1 1/2 precision to preserve bits
        constexpr _Ty _Cm = (_Ty)(22713.0L / 32768.0L);
        constexpr _Ty _Cl = (_Ty) 1.4286068203094172321214581765680755e-6L;
        int _Leftexp;
        _Ty _Rho = _Fabs(_Left, &_Leftexp); // get magnitude and scale factor

        _Ty _Leftn = (_Ty) _Leftexp;
        complex<_Ty> _Tmp(_Rho == 0
                              ? -_Ctraits<_Ty>::_Infv() // log(0) == -INF
                              : _Ctraits<_Ty>::_Isinf(_Rho) ? _Rho // log(INF) == INF
                                                            : _Ctraits<_Ty>::log(_Rho) + _Leftn * _Cl + _Leftn * _Cm,
            _Theta);
        return _Tmp;
    }
}

// FUNCTION TEMPLATE pow
template <class _Ty>
_NODISCARD inline complex<_Ty> pow(const complex<_Ty>& _Left, int _Right) { // return complex ^ integer
    complex<_Ty> _Tmp = _Left;
    auto _Count       = static_cast<unsigned int>(_Right);

    if (_Right < 0) {
        _Count = 0 - _Count; // safe negation as unsigned
    }

    for (complex<_Ty> _Zv = complex<_Ty>(1);; _Tmp *= _Tmp) { // fold in _Left ^ (2 ^ _Count) as needed
        if ((_Count & 1) != 0) {
            _Zv *= _Tmp;
        }

        if ((_Count >>= 1) == 0) {
            return _Right < 0 ? complex<_Ty>(1) / _Zv : _Zv;
        }
    }
}

template <class _Ty>
inline complex<_Ty> _Pow(const _Ty& _Left, const _Ty& _Right) { // return real ^ real
    if (0 <= _Left) {
        return _Ctraits<_Ty>::pow(_Left, _Right);
    } else {
        return exp(_Right * log(complex<_Ty>(_Left)));
    }
}

template <class _Ty>
_NODISCARD inline complex<_Ty> pow(const complex<_Ty>& _Left, const _Ty& _Right) { // return complex ^ real
    if (imag(_Left) == 0) {
        return _Pow(real(_Left), _Right);
    } else {
        return exp(_Right * log(_Left));
    }
}

template <class _Ty>
_NODISCARD inline complex<_Ty> pow(const _Ty& _Left, const complex<_Ty>& _Right) { // return real ^ complex
    if (imag(_Right) == 0) {
        return _Pow(_Left, real(_Right));
    } else if (0 < _Left) {
        return exp(_Right * _Ctraits<_Ty>::log(_Left));
    } else {
        return exp(_Right * log(complex<_Ty>(_Left)));
    }
}

template <class _Ty>
_NODISCARD inline complex<_Ty> pow(const complex<_Ty>& _Left, const complex<_Ty>& _Right) { // return complex ^ complex
    if (imag(_Left) == 0) {
        return pow(real(_Left), _Right);
    } else {
        return exp(_Right * log(_Left));
    }
}

// FUNCTION TEMPLATE sinh
template <class _Ty>
_NODISCARD inline complex<_Ty> sinh(const complex<_Ty>& _Left) { // return sinh(complex)
    return complex<_Ty>(_Ctraits<_Ty>::_Sinh(real(_Left), _Ctraits<_Ty>::cos(imag(_Left))),
        _Ctraits<_Ty>::_Cosh(real(_Left), _Ctraits<_Ty>::sin(imag(_Left))));
}

// FUNCTION TEMPLATE sqrt
template <class _Ty>
_NODISCARD inline complex<_Ty> sqrt(const complex<_Ty>& _Left) { // return sqrt(complex)
    int _Leftexp;
    _Ty _Rho = _Fabs(_Left, &_Leftexp); // get magnitude and scale factor

    if (_Leftexp == 0) {
        return complex<_Ty>(_Rho, _Rho); // argument is zero, INF, or NaN
    } else { // compute in safest quadrant
        _Ty _Realmag = _Ctraits<_Ty>::ldexp(real(_Left) < 0 ? -real(_Left) : real(_Left), -_Leftexp);
        _Rho         = _Ctraits<_Ty>::ldexp(_Ctraits<_Ty>::sqrt(2 * (_Realmag + _Rho)), _Leftexp / 2 - 1);

        if (0 <= real(_Left)) {
            return complex<_Ty>(_Rho, imag(_Left) / (2 * _Rho));
        } else if (imag(_Left) < 0) {
            return complex<_Ty>(-imag(_Left) / (2 * _Rho), -_Rho);
        } else {
            return complex<_Ty>(imag(_Left) / (2 * _Rho), _Rho);
        }
    }
}

// FUNCTION TEMPLATE tanh
template <class _Ty>
_NODISCARD inline complex<_Ty> tanh(const complex<_Ty>& _Left) { // return tanh(complex)
    _Ty _Tv = _Ctraits<_Ty>::tan(imag(_Left));
    _Ty _Sv = _Ctraits<_Ty>::_Sinh(real(_Left), (_Ty)(1));
    _Ty _Bv = _Sv * ((_Ty)(1) + _Tv * _Tv);
    _Ty _Dv = (_Ty)(1) + _Bv * _Sv;

    if (_Ctraits<_Ty>::_Isinf(_Dv)) {
        return complex<_Ty>(_Sv < (_Ty) 0 ? (_Ty)(-1) : (_Ty)(1), _Tv * (_Ty)(0));
    } else {
        return complex<_Ty>((_Ctraits<_Ty>::sqrt((_Ty)(1) + _Sv * _Sv)) * _Bv / _Dv, _Tv / _Dv);
    }
}

// FUNCTION TEMPLATE arg
template <class _Ty>
_NODISCARD inline _Ty arg(const complex<_Ty>& _Left) { // return phase angle of complex as real
    return _Ctraits<_Ty>::atan2(imag(_Left), real(_Left));
}

// FUNCTION TEMPLATE conj
template <class _Ty>
_NODISCARD inline complex<_Ty> conj(const complex<_Ty>& _Left) { // return complex conjugate
    return complex<_Ty>(real(_Left), -imag(_Left));
}

// FUNCTION TEMPLATE proj
template <class _Ty>
_NODISCARD inline complex<_Ty> proj(const complex<_Ty>& _Left) { // return complex projection
    return _Ctraits<_Ty>::_Isinf(real(_Left)) || _Ctraits<_Ty>::_Isinf(imag(_Left))
               ? complex<_Ty>(_Ctraits<_Ty>::_Infv(), imag(_Left) < 0 ? -(_Ty) 0 : (_Ty) 0)
               : _Left;
}

// FUNCTION TEMPLATE cos
template <class _Ty>
_NODISCARD inline complex<_Ty> cos(const complex<_Ty>& _Left) { // return cos(complex)
    return complex<_Ty>(_Ctraits<_Ty>::_Cosh(imag(_Left), _Ctraits<_Ty>::cos(real(_Left))),
        -_Ctraits<_Ty>::_Sinh(imag(_Left), _Ctraits<_Ty>::sin(real(_Left))));
}

// FUNCTION TEMPLATE log10
template <class _Ty>
_NODISCARD inline complex<_Ty> log10(const complex<_Ty>& _Left) { // return log10(complex)
    return log(_Left) * (_Ty) 0.43429448190325182765112891891660508L;
}

// FUNCTION TEMPLATE norm
template <class _Ty>
_NODISCARD inline _Ty norm(const complex<_Ty>& _Left) { // return squared magnitude
    return real(_Left) * real(_Left) + imag(_Left) * imag(_Left);
}

// FUNCTION TEMPLATE polar
template <class _Ty>
_NODISCARD inline complex<_Ty> polar(const _Ty& _Rho, const _Ty& _Theta) { // return _Rho * exp(i * _Theta) as complex
    return complex<_Ty>(_Rho * _Ctraits<_Ty>::cos(_Theta), _Rho * _Ctraits<_Ty>::sin(_Theta));
}

template <class _Ty>
_NODISCARD inline complex<_Ty> polar(const _Ty& _Rho) { // return _Rho * exp(i * 0) as complex
    return complex<_Ty>(_Rho, (_Ty) 0);
}

// FUNCTION TEMPLATE sin
template <class _Ty>
_NODISCARD inline complex<_Ty> sin(const complex<_Ty>& _Left) { // return sin(complex)
    return complex<_Ty>(_Ctraits<_Ty>::_Cosh(imag(_Left), _Ctraits<_Ty>::sin(real(_Left))),
        _Ctraits<_Ty>::_Sinh(imag(_Left), _Ctraits<_Ty>::cos(real(_Left))));
}

// FUNCTION TEMPLATE tan
template <class _Ty>
_NODISCARD inline complex<_Ty> tan(const complex<_Ty>& _Left) { // return tan(complex)
    complex<_Ty> _Zv(tanh(complex<_Ty>(-imag(_Left), real(_Left))));
    return complex<_Ty>(imag(_Zv), -real(_Zv));
}

// ADDITIONAL OVERLOADS
template <class _Ty>
struct _Promote_to_float { // promote integral to double
    using type = conditional_t<is_integral_v<_Ty>, double, _Ty>;
};

#define _GENERIC_MATHC0X(FUN, VAL)                                      \
    template <class _Ty, class = enable_if_t<is_arithmetic_v<_Ty>>>     \
    _NODISCARD inline typename _Promote_to_float<_Ty>::type FUN(_Ty) {  \
        return static_cast<typename _Promote_to_float<_Ty>::type>(VAL); \
    }

#define _GENERIC_MATHC1X(FUN, VAL)                                           \
    template <class _Ty, class = enable_if_t<is_arithmetic_v<_Ty>>>          \
    _NODISCARD inline typename _Promote_to_float<_Ty>::type FUN(_Ty _Left) { \
        return static_cast<typename _Promote_to_float<_Ty>::type>(VAL);      \
    }

_GENERIC_MATHC0X(arg, 0)
_GENERIC_MATHC0X(imag, 0)
_GENERIC_MATHC1X(real, _Left)

_GENERIC_MATHC1X(norm, (_Left * _Left))

_GENERIC_MATHC1X(conj, _Left)
_GENERIC_MATHC1X(proj, _Left)

#undef _GENERIC_MATHC0X
#undef _GENERIC_MATHC1X

// FUNCTION TEMPLATE pow
template <class _Ty1, class _Ty2>
_NODISCARD inline complex<_Common_float_type_t<_Ty1, _Ty2>> pow(
    const complex<_Ty1>& _Left, const complex<_Ty2>& _Right) { // bring mixed types to a common type
    using type = complex<_Common_float_type_t<_Ty1, _Ty2>>;
    return _STD pow(type(_Left), type(_Right));
}

template <class _Ty1, class _Ty2>
_NODISCARD inline complex<_Common_float_type_t<_Ty1, _Ty2>> pow(
    const complex<_Ty1>& _Left, const _Ty2& _Right) { // bring mixed types to a common type
    using type = complex<_Common_float_type_t<_Ty1, _Ty2>>;
    return _STD pow(type(_Left), type(_Right));
}

template <class _Ty1, class _Ty2>
_NODISCARD inline complex<_Common_float_type_t<_Ty1, _Ty2>> pow(
    const _Ty1& _Left, const complex<_Ty2>& _Right) { // bring mixed types to a common type
    using type = complex<_Common_float_type_t<_Ty1, _Ty2>>;
    return _STD pow(type(_Left), type(_Right));
}

template <class _Ty1, class _Ty2, class = enable_if_t<is_integral_v<_Ty1> && is_integral_v<_Ty2>>>
_NODISCARD inline complex<_Ty1> pow(
    const complex<_Ty1>& _Left, _Ty2& _Right) { // raise Gaussian integer to an integer power
    using type = complex<_Ty1>;

    type _Ans = type(1, 0);

    if (_Right < 0) {
        _Ans = type(0, 0); // ignore 1/type(0, 0) error
    } else if (0 < _Right) { // raise to a positive power
        for (type _Factor = _Left;; _Factor *= _Factor) { // fold in _Left^(2^N))
            if ((_Right & 1) != 0) {
                _Ans *= _Factor;
            }

            if ((_Right >>= 1) == 0) {
                break;
            }
        }
    }
    return _Ans;
}

// FUNCTION TEMPLATE operator>>
template <class _Ty, class _Elem, class _Tr>
inline basic_istream<_Elem, _Tr>& operator>>(
    basic_istream<_Elem, _Tr>& _Istr, complex<_Ty>& _Right) { // extract a complex<_Ty>
    const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Istr.getloc());
    _Elem _Ch                      = 0;
    long double _Real              = 0;
    long double _Imag              = 0;

    if (_Istr >> _Ch && _Ch != _Ctype_fac.widen('(')) { // no leading '(', treat as real only
        _Istr.putback(_Ch);
        _Istr >> _Real;
        _Imag = 0;
    } else if (_Istr >> _Real >> _Ch && _Ch != _Ctype_fac.widen(',')) {
        if (_Ch == _Ctype_fac.widen(')')) {
            _Imag = 0; // (real)
        } else { // no trailing ')' after real, treat as bad field
            _Istr.putback(_Ch);
            _Istr.setstate(ios_base::failbit);
        }
    } else if (_Istr >> _Imag >> _Ch && _Ch != _Ctype_fac.widen(')')) { // no imag or trailing ')', treat as bad field
        _Istr.putback(_Ch);
        _Istr.setstate(ios_base::failbit);
    }

    if (!_Istr.fail()) { // store valid result
        _Ty _Tyreal((_Ty) _Real), _Tyimag((_Ty) _Imag);
        _Right = complex<_Ty>(_Tyreal, _Tyimag);
    }
    return _Istr;
}

// FUNCTION TEMPLATE operator<<
template <class _Ty, class _Elem, class _Tr>
inline basic_ostream<_Elem, _Tr>& operator<<(
    basic_ostream<_Elem, _Tr>& _Ostr, const complex<_Ty>& _Right) { // insert a complex<_Ty>
    const ctype<_Elem>& _Ctype_fac = _STD use_facet<ctype<_Elem>>(_Ostr.getloc());
    basic_ostringstream<_Elem, _Tr, allocator<_Elem>> _Sstr;

    _Sstr.flags(_Ostr.flags());
    _Sstr.imbue(_Ostr.getloc());
    _Sstr.precision(_Ostr.precision());
    _Sstr << _Ctype_fac.widen('(') << real(_Right) << _Ctype_fac.widen(',') << imag(_Right) << _Ctype_fac.widen(')');

    return _Ostr << _Sstr.str();
}

// complex LITERALS
inline namespace literals {
    inline namespace complex_literals {
        _NODISCARD constexpr complex<long double> operator""il(long double _Val) { // return imaginary _Val
            return complex<long double>(0.0L, static_cast<long double>(_Val));
        }

        _NODISCARD constexpr complex<long double> operator""il(unsigned long long _Val) { // return imaginary _Val
            return complex<long double>(0.0L, static_cast<long double>(_Val));
        }

        _NODISCARD constexpr complex<double> operator""i(long double _Val) { // return imaginary _Val
            return complex<double>(0.0, static_cast<double>(_Val));
        }

        _NODISCARD constexpr complex<double> operator""i(unsigned long long _Val) { // return imaginary _Val
            return complex<double>(0.0, static_cast<double>(_Val));
        }

        _NODISCARD constexpr complex<float> operator""if(long double _Val) { // return imaginary _Val
            return complex<float>(0.0f, static_cast<float>(_Val));
        }

        _NODISCARD constexpr complex<float> operator""if(unsigned long long _Val) { // return imaginary _Val
            return complex<float>(0.0f, static_cast<float>(_Val));
        }
    } // namespace complex_literals
} // namespace literals

_STD_END

#undef _RE
#undef _IM

#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // RC_INVOKED
#endif // _COMPLEX_

/*
 * Copyright (c) by P.J. Plauger. All rights reserved.
 * Consult your license regarding permissions and restrictions.
V6.50:0009 */
